/*
 * Copyright 2006 Centenum Software Solutions, Inc. All rights reserved.
 * CENTENUM PROPRIETARY/CONFIDENTIAL. 
 */
package com.e7.common;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * A hibernate/Spring framework implementation for IObjectFactory
 * 
 * @author zhang tiange
 * 
 */
public class PMHibernateImpl extends HibernateDaoSupport implements
		IPersistenceManager, ApplicationContextAware {

	private ApplicationContext applicationContext;

	public static IPersistenceManager getInstance() {
		ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
				new String[] { "applicationContext.xml" });
		return (IPersistenceManager) ((BeanFactory) appContext)
				.getBean("persistenceManager");
	}

	@SuppressWarnings("unchecked")
	public <T extends IModelObject> List<T> all(Class<T> clazz) {
		return getHibernateTemplate().find("from " + clazz.getName());
	}

	@Override
	public IModelObject create(Class<? extends IModelObject> clazz) {
		IModelObject bean = (IModelObject) applicationContext
				.getBean(getBeanID(clazz));
		return bean;
	}

	public Criteria createCriteria(Class<? extends IModelObject> clazz) {
		return getHibernateSession().createCriteria(clazz);
	}

	@Override
	public Query createQuery(String hql) {
		return getHibernateSession().createQuery(hql);
	}

	public void delete(IModelObject obj) {
		getHibernateTemplate().delete(obj);
	}

	@Override
	public void deleteAll(Class<? extends IModelObject> clazz) {
		getHibernateTemplate().deleteAll(all(clazz));
	}

	public Integer exists(IModelObject value) {
		@SuppressWarnings("unchecked")
		List<? extends IModelObject> objs = this.getHibernateTemplate()
				.findByExample(value);
		if (objs.size() > 0)
			return objs.get(0).getId();
		return -1;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends IModelObject> T get(Class<T> clazz, Serializable id) {
		T bean = (T) getHibernateTemplate().get(getImplClass(clazz), id);
		return bean;
	}

	private String getBeanID(Class<? extends IModelObject> clazz) {
		int pos = clazz.getName().lastIndexOf('.') + 1;
		return clazz.getName().substring(pos);
	}

	public Session getHibernateSession() {
		return getSession();
	}

	private Class<?> getImplClass(Class<? extends IModelObject> clazz) {
		if (clazz.isInterface())
			return applicationContext.getBean(getBeanID(clazz)).getClass();
		else
			return clazz;
	}

	public IModelObject load(IModelObject e) {
		getHibernateTemplate().load(e, e.getId());
		return e;
	}

	public void logicDelete(IModelObject modelObject) {
		save(modelObject);
	}

	public IModelObject save(IModelObject obj) {
		getSession().saveOrUpdate(obj);
		return obj;
	}

	public void save(IModelObject model, Serializable id) {
		// getSession().persist(model, id);
	}

	@Override
	public void setApplicationContext(ApplicationContext arg0)
			throws BeansException {
		this.applicationContext = arg0;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends IModelObject> List<T> find(Class<T> clazz,
			List<String> fields, List<Object> values) {
		if (fields == null || values == null || fields.size() < 1
				|| fields.size() != values.size())
			return null;
		StringBuilder query = new StringBuilder("from ");
		String field = fields.get(0);
		query.append(clazz.getName()).append(" obj where obj.").append(field)
				.append("=:").append(field);
		for (int i = 1; i < fields.size(); i++) {
			field = fields.get(i);
			query.append(" and obj.").append(field).append("=:").append(field);
		}
		return this.getHibernateTemplate().findByNamedParam(query.toString(),
				(String[]) fields.toArray(), values.toArray());
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends IModelObject> List<T> find(Class<T> clazz, String field,
			Object value) {
		if (field == null || value == null)
			return null;
		StringBuilder query = new StringBuilder("from ");
		query.append(clazz.getName()).append(" obj where obj.")
				.append(field).append("=:").append(field);
		return this.getHibernateTemplate().findByNamedParam(query.toString(),
				field, value);
	}

	@Override
	public void update(IModelObject obj) {
		this.getHibernateTemplate().update(obj);
	}
}
